﻿using Dto;
using Microsoft.Extensions.Caching.Distributed;
using Model;
using StackExchange.Redis;
using System.Text.Json;

namespace Dlpad.Services
{
    public class CacheService : ICacheService
    {
        private readonly IDistributedCache _cache;
        private readonly IConnectionMultiplexer _redis;
        private readonly Random _random = new Random(); // 随机数生成器

        public CacheService(IDistributedCache cache, IConnectionMultiplexer redis)
        {
            _cache = cache;
            _redis = redis;
        }

        public async Task<bool> LoadDictTypesToCacheAsync()
        {
            return true;
        }

        // 直接 Redis 操作（备用方案）
        public async Task SetStringDirectAsync(string key, string value, TimeSpan? expiration = null)
        {
            try
            {
                var db = _redis.GetDatabase();
                await db.StringSetAsync(key, value, expiration);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[REDIS-DIRECT-ERROR] 直接设置缓存失败: {ex.Message}");
                // 回退到标准方法
                await SetStringAsync(key, value, expiration);
            }
        }

        public async Task<string> GetStringDirectAsync(string key)
        {
            try
            {
                var db = _redis.GetDatabase();
                var result = await db.StringGetAsync(key);
                return result.HasValue ? result.ToString() : string.Empty;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[REDIS-DIRECT-ERROR] 直接获取缓存失败: {ex.Message}");
                // 回退到标准方法
                return await GetStringAsync(key);
            }
        }

        public async Task<List<SysDictType>> GetDictTypesFromCacheAsync()
        {
            var json = await GetStringAsync("sys_dict_type_all");
            if (string.IsNullOrEmpty(json))
                return new List<SysDictType>();

            return JsonSerializer.Deserialize<List<SysDictType>>(json) ?? new List<SysDictType>();
        }

        // 基础缓存操作
        public async Task SetStringAsync(string key, string value, TimeSpan? expiration = null)
        {
            var options = new DistributedCacheEntryOptions();
            if (expiration.HasValue)
            {
                options.AbsoluteExpirationRelativeToNow = expiration;
            }

            try
            {
                await _cache.SetStringAsync(key, value, options);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[CACHE-ERROR] 设置缓存失败: {ex.Message}");
            }
        }

        public async Task<string> GetStringAsync(string key)
        {
            try
            {
                // 1. 调用原生方法
                return await _cache.GetStringAsync(key) ?? string.Empty;
            }
            catch (Exception ex) when (ex.Message.Contains("WRONGTYPE"))
            {
                // 2.忽略 hash 类型错误
                Console.WriteLine($"[CACHE-IGNORE] 忽略 hash 类型缓存: {key}");
                return string.Empty;
            }
            catch (Exception ex)
            {
                // 3. 异常降级：Redis宕机或网络超时
                Console.WriteLine($"[CACHE-ERROR] 获取缓存失败: {ex.Message}");
                return string.Empty; // 不抛异常，保证主流程可用
            }
        }

        public async Task RemoveAsync(string key)
        {
            try
            {
                await _cache.RemoveAsync(key);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[CACHE-ERROR] 删除缓存失败: {ex.Message}");
            }
        }

        // 字典数据缓存方法
        public async Task<List<DictDataResponseDto>> GetDictDataByTypeAsync(string dictType)
        {
            var cacheKey = $"Dlpad_dict_data_{dictType}";

            try
            {
                var cachedData = await GetStringAsync(cacheKey);

                if (!string.IsNullOrEmpty(cachedData))
                {
                    try
                    {
                        return JsonSerializer.Deserialize<List<DictDataResponseDto>>(cachedData) ?? new List<DictDataResponseDto>();
                    }
                    catch (JsonException)
                    {
                        await RemoveAsync(cacheKey);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[CACHE-ERROR] 获取字典数据缓存失败: {ex.Message}");
            }

            return new List<DictDataResponseDto>();
        }

        public async Task ClearDictDataCacheAsync(string dictType = null)
        {
            if (string.IsNullOrEmpty(dictType))
            {
                return;
            }
            else
            {
                await RemoveAsync($"Dlpad_dict_data_{dictType}");
            }
        }

        public async Task<List<DictTypeResponseDto>> GetAllDictTypesAsync()
        {
            var cacheKey = "Dlpad_all_dict_types";

            try
            {
                var cachedData = await GetStringAsync(cacheKey);
                if (!string.IsNullOrEmpty(cachedData))
                {
                    return JsonSerializer.Deserialize<List<DictTypeResponseDto>>(cachedData) ?? new List<DictTypeResponseDto>();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[CACHE-ERROR] 获取字典类型缓存失败: {ex.Message}");
            }

            return new List<DictTypeResponseDto>();
        }

        public async Task ClearAllDictCacheAsync()
        {
            await RemoveAsync("Dlpad_all_dict_types");
        }

        /// <summary>
        /// 设置字典数据缓存（带防雪崩随机过期）
        /// </summary>
        public async Task SetDictDataByTypeAsync(string dictType, List<DictDataResponseDto> data)
        {
            var cacheKey = $"Dlpad_dict_data_{dictType}";

            // ★★★ 随机过期时间：22-26小时 ★★★
            var baseExpire = TimeSpan.FromHours(24);
            var randomOffset = TimeSpan.FromHours(_random.Next(-2, 2)) +
                              TimeSpan.FromMinutes(_random.Next(0, 60)); // 再随机分钟

            var finalExpire = baseExpire + randomOffset;

            var json = JsonSerializer.Serialize(data);
            await SetStringAsync(cacheKey, json, finalExpire);

            Console.WriteLine($"[CACHE-SNOW] {dictType} 缓存过期时间: {finalExpire.TotalHours:F2} 小时");
        }

        // 同样为字典类型设置随机过期
        public async Task SetDictTypesAsync(List<DictTypeResponseDto> dictTypes)
        {
            var cacheKey = "Dlpad_all_dict_types";

            var baseExpire = TimeSpan.FromHours(24);
            var randomOffset = TimeSpan.FromHours(_random.Next(-2, 2));

            var json = JsonSerializer.Serialize(dictTypes);
            await SetStringAsync(cacheKey, json, baseExpire + randomOffset);
        }
    }
}